/*********************************************************************************
 *Copyright(C),1996-2022,ZhangJianCe
 *FileName:  CAN_Module.c
 *Author:  ZhangJianCe
 *Version:  V1.0
 *Date: 2022-04-11
 ****************************************Includes***********************************/
#include "CAN_Module.h"
#include "CAN_Config.h"
// #include "Delay.h"

/***************************************Variables***********************************/
CAN_ID_Table_t CAN0_Rx_Config[] = CAN0_Rx_List;
CAN_ID_Table_t CAN1_Rx_Config[] = CAN1_Rx_List;

CAN_Frame_t CAN0_Rx_Buff[sizeof(CAN0_Rx_Config) / sizeof(CAN0_Rx_Config[0])];
CAN_Frame_t CAN1_Rx_Buff[sizeof(CAN1_Rx_Config) / sizeof(CAN1_Rx_Config[0])];
/***************************************Functions***********************************/



CAN_HandleTypeDef * Get_CANHandle(uint8_t Index)
{
	CAN_HandleTypeDef *pcan = (void*)0;
	if(Index == 0)
	{
		pcan = &hcan1;
	}
	else if(Index == 1)
	{
		pcan = &hcan2;
	}
	else
	{
	}
	return pcan;
}


/**
 * @brief CAN Module Initialize
 * @param Channel CAN Channel: 0 , 1
 * @retval 0:fial , 1:success
 * @author  ZhangJianCe
 */
uint8_t CAN_Module_Init(uint8_t Channel)
{
	uint8_t ret;
	uint32_t volatile Notification_type = 0;
	CAN_HandleTypeDef *pcan = Get_CANHandle(Channel);
	CAN_Frame_t * P_Frame_Buff = NULL;
	CAN_ID_Table_t * P_ID_Table = NULL;
	uint8_t CAN_Rx_Num = 0;
	if (Channel == 0)
	{
		pcan->Init.Prescaler = CAN0_PRESCAL;
		pcan->Init.TimeSeg1 = CAN0_TimeSeg1;
		pcan->Init.TimeSeg2 = CAN0_TimeSeg2;
		pcan->RxFifo0MsgPendingCallback = CAN_ISR_Handle;
		Notification_type = CAN_IT_RX_FIFO0_MSG_PENDING;
		P_Frame_Buff = CAN0_Rx_Buff;
		CAN_Rx_Num = sizeof(CAN0_Rx_Config) / sizeof(CAN0_Rx_Config[0]);
		P_ID_Table = CAN0_Rx_Config;
	}
	else if (Channel == 1)
	{
		pcan->Init.Prescaler = CAN1_PRESCAL;
		pcan->Init.TimeSeg1 = CAN1_TimeSeg1;
		pcan->Init.TimeSeg2 = CAN1_TimeSeg2;
		pcan->RxFifo1MsgPendingCallback = CAN_ISR_Handle;
		Notification_type = CAN_IT_RX_FIFO1_MSG_PENDING;
		P_Frame_Buff = CAN1_Rx_Buff;
		CAN_Rx_Num = sizeof(CAN1_Rx_Config) / sizeof(CAN1_Rx_Config[0]);
		P_ID_Table = CAN1_Rx_Config;
	}
	else
	{
		return 0;
	}
	for (uint32_t i = 0; i < CAN_Rx_Num; i++)
	{
		P_Frame_Buff[i].ID = P_ID_Table[i].ID;
		P_Frame_Buff[i].IDE = P_ID_Table[i].isExtendedFrame;
		P_Frame_Buff[i].RTR = P_ID_Table[i].isRemoteFrame;
		P_Frame_Buff[i].CallBack = NULL;
		for (uint8_t j = 0; j < 8; j++)
		{
			P_Frame_Buff[i].Data[j] = 0;
		}
	}
	

	if (HAL_CAN_Init(pcan) != HAL_OK)
	{
		Error_Handler();
	}else
	{}
	
	ret = HAL_CAN_ActivateNotification(pcan, Notification_type);
	CAN_Filter_Init(pcan);
	ret += HAL_CAN_Start(pcan);
	return !ret;
}

/**
 * @brief CAN Filter Initialize
 * @param hcan CAN instance Point
 * @retval None
 * @author  ZhangJianCe
 */
void CAN_Filter_Init(CAN_HandleTypeDef *hcan)
{

	/*CAN筛选器结构体定义*/
	CAN_FilterTypeDef CAN_Filter;
	CAN_Filter.SlaveStartFilterBank = 14;
	uint8_t Filter_Offset = 0;

	/*CAN标识符过滤列表指针*/
	CAN_ID_Table_t *CAN_Config;
	uint8_t CAN_Rx_Num = 0;
	if (hcan->Instance == hcan1.Instance)
	{
		Filter_Offset = 0;
		CAN_Config = CAN0_Rx_Config;
		CAN_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
		CAN_Rx_Num = sizeof(CAN0_Rx_Config) / sizeof(CAN0_Rx_Config[0]);
	}
	else if (hcan->Instance == hcan2.Instance)
	{
		Filter_Offset = 14;
		CAN_Config = CAN1_Rx_Config;
		CAN_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO1;
		CAN_Rx_Num = sizeof(CAN1_Rx_Config) / sizeof(CAN1_Rx_Config[0]);
	}
	else
	{
		__disable_irq();
		while (1)
			;
	}

	/*使用标识符列表模式过滤*/
	CAN_Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN_Filter.FilterScale = CAN_FILTERSCALE_16BIT;
	for (uint8_t i = 0; i < CAN_Rx_Num; i++)
	{
		if (CAN_Config[i].isExtendedFrame)
		{
			CAN_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
			break;
		}
	}

	uint8_t index = 0;
	/*16位过滤模式*/
	if (CAN_Filter.FilterScale == CAN_FILTERSCALE_16BIT)
	{
		for (uint8_t i = 0; i < CAN_Rx_Num;)
		{
			index = i % 4;
			CAN_Filter.FilterBank = Filter_Offset + (i / 4);
			switch (index)
			{
			case 0:
			{
				CAN_Filter.FilterIdLow = (uint16_t)((CAN_Config[i].ID << 5) | (CAN_Config[i].isRemoteFrame << 4) | (CAN_Config[i].isExtendedFrame << 3));
				break;
			}
			case 1:
			{
				CAN_Filter.FilterMaskIdLow = (uint16_t)((CAN_Config[i].ID << 5) | (CAN_Config[i].isRemoteFrame << 4) | (CAN_Config[i].isExtendedFrame << 3));
				break;
			}
			case 2:
			{
				CAN_Filter.FilterIdHigh = (uint16_t)((CAN_Config[i].ID << 5) | (CAN_Config[i].isRemoteFrame << 4) | (CAN_Config[i].isExtendedFrame << 3));
				break;
			}
			case 3:
			{
				CAN_Filter.FilterMaskIdHigh = (uint16_t)((CAN_Config[i].ID << 5) | (CAN_Config[i].isRemoteFrame << 4) | (CAN_Config[i].isExtendedFrame << 3));
				break;
			}
			}
			i++;
			if ((i % 4 == 0) || (i >= CAN_Rx_Num))
			{
				CAN_Filter.FilterActivation = CAN_FILTER_ENABLE;
				HAL_CAN_ConfigFilter(hcan, &CAN_Filter);
			}
		}
	}
	else /*32位过滤模式*/
	{
		for (uint8_t i = 0; i < CAN_Rx_Num;)
		{
			index = i % 2;
			CAN_Filter.FilterBank = Filter_Offset + (i / 2);
			switch (index)
			{
			case 0:
			{
				if (CAN_Config[i].isExtendedFrame)
				{
					CAN_Filter.FilterIdHigh = (uint16_t)(((CAN_Config[i].ID << 3) >> 16) & 0xFFFF);
					CAN_Filter.FilterIdLow = (uint16_t)(((CAN_Config[i].ID << 3) & 0xFFFF) |
														(CAN_Config[i].isExtendedFrame << 2) | (CAN_Config[i].isRemoteFrame << 1));
				}
				else
				{
					CAN_Filter.FilterIdHigh = (uint16_t)((CAN_Config[i].ID << 5) & 0xFFFF);
					CAN_Filter.FilterIdLow = (uint16_t)((CAN_Config[i].isExtendedFrame << 2) | (CAN_Config[i].isRemoteFrame << 1));
				}
				break;
			}
			case 1:
			{
				if (CAN_Config[i].isExtendedFrame)
				{
					CAN_Filter.FilterMaskIdHigh = (uint16_t)(((CAN_Config[i].ID << 3) >> 16) & 0xFFFF);
					CAN_Filter.FilterMaskIdLow = (uint16_t)(((CAN_Config[i].ID << 3) & 0xFFFF) |
														 (CAN_Config[i].isExtendedFrame << 2) | (CAN_Config[i].isRemoteFrame << 1));
				}
				else
				{
					CAN_Filter.FilterMaskIdHigh = (uint16_t)((CAN_Config[i].ID << 5) & 0xFFFF);
					CAN_Filter.FilterMaskIdLow = (uint16_t)((CAN_Config[i].isExtendedFrame << 2) | (CAN_Config[i].isRemoteFrame << 1));
				}
				break;
			}
			}
			i++;
			if ((i % 2 == 0) || (i >= CAN_Rx_Num))
			{
				CAN_Filter.FilterActivation = CAN_FILTER_ENABLE;
				HAL_CAN_ConfigFilter(hcan, &CAN_Filter);
			}
		}
	}
}

/**
 * @brief Check CAN BUS Idle Status
 * @param Channel CAN Channel: 0 , 1
 * @retval 0:Busy,1:Idle
 * @author  ZhangJianCe
 */
uint8_t CAN_Module_CheckIdle(uint8_t Channel)
{
	CAN_HandleTypeDef *pcan = Get_CANHandle(Channel);

	if (HAL_CAN_GetTxMailboxesFreeLevel(pcan) > 0)
		return 1;
	else
		return 0;
}

/**
 * @brief Send CAN Data
 * @param Channel CAN channel 0 or 1
 * @param ID CAN ID
 * @param IDE 0:standard ID,1：Extend ID
 * @param RTR 0:Data Frame,1：Remote Frame
 * @param Data Data point
 * @param Len CAN DLC
 * @retval 0:fail , 1:success
 * @author  ZhangJianCe
 */
uint8_t CAN_Module_Write(uint8_t Channel, uint32_t ID, uint8_t IDE, uint8_t RTR, uint8_t *Data, uint8_t Len)
{
	uint32_t SendMB;
	CAN_HandleTypeDef *pcan = Get_CANHandle(Channel);
	CAN_TxHeaderTypeDef pHeader;

	if (0==CAN_Module_CheckIdle(Channel))
	{
		return 0;
	}

	pHeader.IDE = IDE == 1 ? CAN_ID_EXT : CAN_ID_STD;
	if (pHeader.IDE == CAN_ID_STD)
	{
		pHeader.StdId = ID;
	}
	else
	{
		pHeader.StdId = ID >> 18;
		pHeader.ExtId = ID & 0x3ffff;
	}
	pHeader.DLC = Len;
	pHeader.RTR = RTR == 1 ? CAN_RTR_REMOTE : CAN_RTR_DATA;

	HAL_CAN_AddTxMessage(pcan, &pHeader, Data, &SendMB);
	return 1;
}

/**
 * @brief Read CAN Data
 * @param Channel CAN channel 0 or 1
 * @param ID CAN ID
 * @param IDE 0:standard ID,1：Extend ID
 * @param RTR 0:Data Frame,1：Remote Frame
 * @param Data Data point
 * @retval -1:fail , x:DLC
 * @author  ZhangJianCe
 */
int8_t CAN_Module_Read(uint8_t Channel, \
		uint32_t ID, uint8_t IDE, \
		uint8_t RTR, uint8_t *Data)
{
	uint8_t ID_Index;
	uint8_t Max_Index;
	CAN_Frame_t *P_Frame;
	// CAN_HandleTypeDef *pcan = Get_CANHandle(Channel);
	// uint32_t IT_Mask = 0;

	if (Channel == 0)
	{
		// IT_Mask = CAN_IT_RX_FIFO0_MSG_PENDING;
		P_Frame = CAN0_Rx_Buff;
		Max_Index = sizeof(CAN0_Rx_Buff) / sizeof(CAN0_Rx_Buff[0]);
	}
	else if (Channel == 1)
	{
		// IT_Mask = CAN_IT_RX_FIFO1_MSG_PENDING;
		P_Frame = CAN1_Rx_Buff;
		Max_Index = sizeof(CAN1_Rx_Buff) / sizeof(CAN1_Rx_Buff[0]);
	}
	else
	{
		return -1;
	}

	for (ID_Index = 0; ID_Index < Max_Index; ID_Index++)
	{
		if (P_Frame[ID_Index].ID == ID)
		{
			break;
		}
	}
	if (ID_Index >= Max_Index)
	{
		return -1;
	}
	else
	{
		if((P_Frame[ID_Index].IDE==IDE)&&(P_Frame[ID_Index].RTR==RTR))
		{
			/*读取数据前关闭CAN接收中断*/
			// __HAL_CAN_DISABLE_IT(pcan,IT_Mask);
			for (uint8_t i = 0; i < P_Frame[ID_Index].DLC; i++)
			{
				Data[i] = P_Frame[ID_Index].Data[i];
			}
			P_Frame[ID_Index].ID = 0;
			/*读取数据完毕重新开启CAN接收中断*/
			// __HAL_CAN_ENABLE_IT(pcan,IT_Mask);
			return P_Frame[ID_Index].DLC;
		}
		else
		{
			return -1;
		}
	}
}

uint8_t CAN_Moudle_Read_IT(uint8_t Channel,uint32_t ID, uint8_t IDE, uint8_t RTR,CAN_Rx_CallBack_t Handle)
{
	uint8_t ID_Index;
	uint8_t Max_Index;
	CAN_Frame_t *P_Frame;
	if (Channel == 0)
	{
		P_Frame = CAN0_Rx_Buff;
		Max_Index = sizeof(CAN0_Rx_Buff) / sizeof(CAN0_Rx_Buff[0]);
	}
	else if (Channel == 1)
	{
		P_Frame = CAN1_Rx_Buff;
		Max_Index = sizeof(CAN1_Rx_Buff) / sizeof(CAN1_Rx_Buff[0]);
	}
	else
	{
		return 0;
	}

	for (ID_Index = 0; ID_Index < Max_Index; ID_Index++)
	{
		if (P_Frame[ID_Index].ID == ID)
		{
			break;
		}
	}
	if (ID_Index >= Max_Index)
	{
		return 0;
	}
	else
	{
		P_Frame[ID_Index].CallBack = Handle;
		return 1;
	}
}

/**
 * @brief Copy CAN Date to Buff From Fifo
 * @param hcan CAN instance Point
 * @retval None
 * @author  ZhangJianCe
 */
void CAN_ISR_Handle(CAN_HandleTypeDef *hcan)
{
	/*先接收数据到缓冲中*/
	CAN_RxHeaderTypeDef Rx_Buff_Head;
	uint8_t ID_Index = 0;
	uint8_t Data[8];
	CAN_Frame_t *P_Frame;
	uint32_t Filter_Index;
	if (hcan->Instance ==  hcan1.Instance)
	{
		P_Frame = CAN0_Rx_Buff;
		Filter_Index = CAN_RX_FIFO0;
	}
	else if (hcan->Instance ==  hcan2.Instance)
	{
		P_Frame = CAN1_Rx_Buff;
		Filter_Index = CAN_RX_FIFO1;
	}
	else
	{
		return;
	}

	HAL_CAN_GetRxMessage(hcan, Filter_Index, &Rx_Buff_Head, Data);
	ID_Index = Rx_Buff_Head.FilterMatchIndex;
	if(P_Frame[ID_Index].CallBack)
	{
		/*调用CAN中断回调函数*/
		P_Frame[ID_Index].CallBack(Data,Rx_Buff_Head.DLC);
		/*清空中断回调指针*/
		// P_Frame[ID_Index].CallBack = (void*)0;
		return;
	}
	else
	{
		P_Frame[ID_Index].IDE = (uint8_t)Rx_Buff_Head.IDE;
		P_Frame[ID_Index].RTR = (uint8_t)Rx_Buff_Head.RTR;
		P_Frame[ID_Index].DLC = (uint8_t)Rx_Buff_Head.DLC;
		if (P_Frame[ID_Index].IDE != 0)
		{
			P_Frame[ID_Index].ID = Rx_Buff_Head.ExtId;
		}
		else
		{
			P_Frame[ID_Index].ID = Rx_Buff_Head.StdId;
		}
		for (uint8_t i = 0; i < P_Frame[ID_Index].DLC; i++)
		{
			P_Frame[ID_Index].Data[i] = Data[i];
		}
	}
}
